package com.java.basis.thread.cas.atomic;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 多个线程访问数组内元素的线程安全问题
 *
 * @author wangning
 * @create 2022-01-28 16:35
 */
public class Test05 {
	public static void main(String[] args) {
		demo(
				() -> new int[10],
				array -> array.length,
				(array, index) -> array[index]++,
				array -> System.out.println(Arrays.toString(array))
		);

		demo(
				() -> new AtomicIntegerArray(10),
				array -> array.length(),
				(array, index) -> array.getAndIncrement(index),
				array -> System.out.println(array)
		);

		demo(
				() -> new AtomicIntegerArray(10),
				AtomicIntegerArray::length,
				AtomicIntegerArray::getAndIncrement,
				System.out::println
		);

	}

	/**
	 * 函数式编程
	 * Supplier 提供者 无中生有 ()->结果
	 * Function 函数 一个参数一个结果 （参数）->结果
	 * BiFunction (参数1，参数2)->结果
	 * Consumer 消费者 一个参数没有结果 （参数）->
	 * BiConsumer （参数1，参数2) ->
	 *
	 *
	 * @param arraySupplier 提供数组、可以是线程不安全的数组或线程安全数组
	 * @param lengthFun 获取数组长度的方法
	 * @param putConsumer 自增方法，回传 array，index
	 * @param printConsumer 打印数组的方法
	 * @param <T>
	 */
	private static <T> void demo(Supplier<T> arraySupplier,
								 Function<T, Integer> lengthFun,
								 BiConsumer<T, Integer> putConsumer,
								 Consumer<T> printConsumer) {
		List<Thread> ts = new ArrayList<>();
		T array = arraySupplier.get();
		int length = lengthFun.apply(array);
		for (int i = 0; i < length; i++) {
			//每个线程对数组操作 10000 次
			ts.add(new Thread(() -> {
				for (int j = 0; j < 10000; j++) {
					putConsumer.accept(array, j % length);
				}
			}));
		}
		ts.forEach(Thread::start);
		ts.forEach((t) -> {
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
		printConsumer.accept(array);


	}

	
}
